// Copyright (c) 2020 Presto Labs Pte. Ltd.
// Author: donggu

#pragma once

#include <map>
#include <string>
#include <utility>
#include <vector>

#include <boost/algorithm/string.hpp>
#include <cxxopts.hpp>
#include <nlohmann/json.hpp>
#include <toml.hpp>

#include "coin2/app/driver.pb.h"
#include "coin2/base/config/app_config.h"
#include "coin2/base/log.h"
#include "coin2/base/time.h"

namespace coin2::base::config {

std::pair<int64_t, int64_t> ParseIntervalConfig(const toml::value& v);

void AddJsonOptions(cxxopts::Options* opt);
void AddDriverOptions(cxxopts::Options* opt);
void AddIntervalOptions(cxxopts::Options* opt);
void AddProductOptions(cxxopts::Options* opt);
void AddLogArchiveOptions(cxxopts::Options* opt);
void AddFeedArchiveOptions(cxxopts::Options* opt);

std::vector<nlohmann::json> ParseJsonOptions(const cxxopts::ParseResult& res);

bool ParseDriverOptions(const cxxopts::ParseResult& res, coin2::app::DriverConfig* config);
void ParseJsonOptions(const cxxopts::ParseResult& res, coin2::app::DriverConfig* config);

void ParseIntervalOptions(const cxxopts::ParseResult& res, coin2::base::IntervalConfig* config);

std::map<std::string, std::vector<std::string>> ParseProductList(const std::string& s);

// FeedManagerConfig or OrderManagerConfig
template <typename TManagerConfig>
void ParseProductOptions(const cxxopts::ParseResult& res, TManagerConfig* config) {
  if (res.count("groups")) {
    auto map = ParseProductList(res["groups"].as<std::string>());

    for (auto& [mea, symbols] : map) {
      auto vec = (*config->mutable_exchanges())[mea].mutable_products()->mutable_groups();
      *vec = {symbols.begin(), symbols.end()};
    }
  }
  if (res.count("natives")) {
    auto map = ParseProductList(res["natives"].as<std::string>());
    for (auto& [mea, symbols] : map) {
      auto vec = (*config->mutable_exchanges())[mea].mutable_products()->mutable_natives();
      *vec = {symbols.begin(), symbols.end()};
    }
  }
  if (res.count("norms")) {
    auto map = ParseProductList(res["norms"].as<std::string>());
    for (auto& [mea, symbols] : map) {
      auto vec = (*config->mutable_exchanges())[mea].mutable_products()->mutable_norms();
      *vec = {symbols.begin(), symbols.end()};
    }
  }
}

void AddDateOption(cxxopts::Options* opt, const char* flag = "date");
int64_t ParseDateOption(const cxxopts::ParseResult& res, const char* flag = "date");

}  // namespace coin2::base::config
